package com.lagou.client.utils;

import com.alibaba.fastjson.JSON;
import com.lagou.api.com.RpcRequest;
import com.lagou.api.com.RpcResponse;
import com.lagou.rpc.core.ProviderNode;
import com.lagou.rpc.core.ProviderWatcher;
import com.lagou.rpc.core.config.RpcConfig;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


@Component
@Log4j2
public class RpcClientProxy   {





    @Autowired
    private ProviderWatcher providerWatcher;


    private Map<String,List<ProviderNode>>  cacheMap = new HashMap<>();

    /**
     * 初始化构建
     */
    @PostConstruct
    public void init(){

    }


    /**
     * 获取轮训服务
     * @param serviceName
     * @return
     */
    public ProviderNode round(String serviceName) {
        PriorityQueue<ProviderNode>  hosts =  providerWatcher.getProvider().get(serviceName);
        return hosts.peek();
    }


    /**
     * 处理请求
     * @param rpcRequest
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public Object handle(RpcRequest rpcRequest , Method method) throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();
        ProviderNode  providerNode = round(rpcRequest.getClassName());
        String providerUrl = providerNode.getProviderUrl();
        String ip =    providerUrl.split(":")[0];
        String port =  providerUrl.split(":")[1];
        RpcClient  rpcClient =  new RpcClient(ip, Integer.parseInt(port));
        try {
            String  response = (String) rpcClient.send(JSON.toJSONString(rpcRequest));
            RpcResponse rpcResponse = JSON.parseObject(response,RpcResponse.class);
            Long endTime = System.currentTimeMillis();
            providerWatcher.uploadProvider(providerNode,startTime,endTime);
            if (!StringUtils.isEmpty( rpcResponse.getError()) ){
                throw new RuntimeException(rpcResponse.getError());
            }else {
                return JSON.parseObject(rpcResponse.getResult().toString(), method.getReturnType());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            rpcClient.close();
        }
        return null;
    }


    public  Object createProxy(Class clazz){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                RpcRequest rpcRequest = new RpcRequest();
                rpcRequest.setRequestId(UUID.randomUUID().toString());
                rpcRequest.setClassName(method.getDeclaringClass().getName());
                rpcRequest.setMethodName(method.getName());
                rpcRequest.setParameters(args);
                rpcRequest.setParameterTypes(method.getParameterTypes());
                return handle(rpcRequest , method);
            }
        });
    }
}
